package ImageProcessing;


import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;

/**
 * Created by doris on 2016/10/26.
 */
public class ImageProcessing {
    private String srcImagePath = null;

    public ImageProcessing(String srcImagePath) {
        this.srcImagePath = srcImagePath;
    }

    //对图片裁剪，并把裁剪新图片保存
    public void cropImage(String outPath, int x, int y, int width, int height,
                          String readFormat, String writeFormat) throws IOException {
        ImageInputStream input = ImageIO.createImageInputStream(new FileInputStream(srcImagePath));
        Iterator iterator = ImageIO.getImageReadersByFormatName(readFormat);
        ImageReader reader = (ImageReader) iterator.next();
        reader.setInput(input, true);
        ImageReadParam param = reader.getDefaultReadParam();
        //定义一个矩形
        Rectangle rectangle = new Rectangle(x, y, width, height);
        //提供一个 BufferedImage，将其用作解码像素数据的目标。
        param.setSourceRegion(rectangle);
        BufferedImage output = reader.read(0, param);
        //保存新图片
        ImageIO.write(output, writeFormat, new File(outPath));
        input.close();
    }

    //长高等比例缩放图片
    public void changeImageEqualProportion(String outImagePath, int ratio) throws IOException {
        BufferedImage src = ImageIO.read(new File(srcImagePath));
        int width = src.getWidth();
        int height = src.getHeight();
        int[] imageArray = new int[width * height];
        src.getRGB(0, 0, width, height, imageArray, 0, width);
        BufferedImage temp = null;
        if (ratio < 0) {
            ratio = -ratio;
            // 缩小边长
            temp = new BufferedImage(width / ratio, height / ratio, BufferedImage.TYPE_INT_RGB);
            // 绘制 缩小  后的图片
            temp.setRGB(0,0, width / ratio, height / ratio,imgScale(imageArray,width,height,width / ratio,height / ratio),0,width / ratio);
//            temp.getGraphics().drawImage(src, 0, 0, width / ratio, height / ratio, null);
        } else if (ratio > 0) {
            // 放大边长
            temp = new BufferedImage(width * ratio, height * ratio, BufferedImage.TYPE_INT_RGB);
            //绘制放大后的图片
            temp.setRGB(0,0, width * ratio, height * ratio,imgScale(imageArray,width,height,width * ratio,height * ratio),0,width * ratio);
//            temp.getGraphics().drawImage(src, 0, 0, width * ratio, height * ratio, null);
        } else {
            return;
        }
        FileOutputStream out = new FileOutputStream(outImagePath);
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(temp);
        out.close();
    }

    //重置图片长宽
    public void resetImageEqualProportion(String outImagePath, int nowHeight, int nowWidth) throws IOException {
        BufferedImage src = ImageIO.read(new File(srcImagePath));
        int width = src.getWidth();
        int height = src.getHeight();
        int[] imageArray = new int[width * height];
        src.getRGB(0, 0, width, height, imageArray, 0, width);

        BufferedImage temp = null;
        temp = new BufferedImage(nowWidth, nowHeight, BufferedImage.TYPE_INT_RGB);
        temp.setRGB(0,0, nowWidth, nowHeight,imgScale(imageArray,width,height,nowWidth,nowHeight),0,nowWidth);

        FileOutputStream out = new FileOutputStream(outImagePath);
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(temp);
        out.close();
    }

    //双线性插值算法
    private int[] imgScale(int[] inPixelsData, int srcW, int srcH, int destW, int destH) {
        double[][][] input3DData = processOneToThreeDeminsion(inPixelsData, srcH, srcW);
        int[][][] outputThreeDeminsionData = new int[destH][destW][4];
        float rowRatio = ((float)srcH)/((float)destH);
        float colRatio = ((float)srcW)/((float)destW);
        for(int row=0; row<destH; row++) {
            // convert to three dimension data
            double srcRow = ((float)row)*rowRatio;
            double j = Math.floor(srcRow);
            double t = srcRow - j;
            for(int col=0; col<destW; col++) {
                double srcCol = ((float)col)*colRatio;
                double k = Math.floor(srcCol);
                double u = srcCol - k;
                double coffiecent1 = (1.0d-t)*(1.0d-u);
                double coffiecent2 = (t)*(1.0d-u);
                double coffiecent3 = t*u;
                double coffiecent4 = (1.0d-t)*u;
                outputThreeDeminsionData[row][col][0] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][0] +
                        coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][0] +
                        coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0] +
                        coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0]); // alpha
                outputThreeDeminsionData[row][col][1] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][1] +
                        coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][1] +
                        coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1] +
                        coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1]); // red
                outputThreeDeminsionData[row][col][2] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][2] +
                        coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][2] +
                        coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2] +
                        coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2]);// green

                outputThreeDeminsionData[row][col][3] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][3] +
                        coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][3] +
                        coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3] +
                        coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3]); // blue
            }
        }
        return convertToOneDim(outputThreeDeminsionData, destW, destH);
    }

    //双线性插值所需的方法

    private int getClip(int x, int max, int min) {
        return x>max ? max : x<min? min : x;
    }

    //线性插值所需的方法

    public int[] convertToOneDim(int[][][] data, int imgCols, int imgRows) {
        int[] oneDPix = new int[imgCols * imgRows * 4];
        for (int row = 0, cnt = 0; row < imgRows; row++) {
            for (int col = 0; col < imgCols; col++) {
                oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000)
                        | ((data[row][col][1] << 16) & 0x00FF0000)
                        | ((data[row][col][2] << 8) & 0x0000FF00)
                        | ((data[row][col][3]) & 0x000000FF);
                cnt++;
            }
        }
        return oneDPix;
    }
    private double [][][] processOneToThreeDeminsion(int[] oneDPix2, int imgRows, int imgCols) {
        double[][][] tempData = new double[imgRows][imgCols][4];
        for(int row=0; row<imgRows; row++) {
            int[] aRow = new int[imgCols];
            for (int col = 0; col < imgCols; col++) {
                int element = row * imgCols + col;
                aRow[col] = oneDPix2[element];
            }
            for(int col=0; col<imgCols; col++) {
                tempData[row][col][0] = (aRow[col] >> 24) & 0xFF; // alpha
                tempData[row][col][1] = (aRow[col] >> 16) & 0xFF; // red
                tempData[row][col][2] = (aRow[col] >> 8) & 0xFF;  // green
                tempData[row][col][3] = (aRow[col]) & 0xFF;       // blue
            }
        }
        return tempData;
    }
}
